package com.github.zyf.ioaj.network.utils;

/**
 * @author zyf
 */
public class ActFunction {

    /**
     * 激活函数： sigmoid 函数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double sigmoid(double param) {
        return 1 / (1 + Math.exp(-param));
    }

    /**
     * sigmoid 函数导数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double dSigmoid(double param) {
        double f = sigmoid(param);
        return f * (1 - f);
    }

    /**
     * 激活函数： swish 函数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double swish(double param) {
        return param * sigmoid(param);
    }

    /**
     * swish 函数导数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double dSwish(double param) {
        return sigmoid(param) + param * dSigmoid(param);
    }

    /**
     * 激活函数： tanh 函数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double tanh(double param) {
        return Math.tanh(param);
    }

    /**
     * tanh 函数导数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double dTanh(double param) {
        double f = tanh(param);
        return 1 - f * f;
    }

    /**
     * 激活函数： ReLU 函数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double ReLU(double param) {
        return param >= 0 ? param : 0.0;
    }

    /**
     * ReLU 函数导数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double dReLU(double param) {
        return param >= 0 ? 1.0 : 0.0;
    }

    /**
     * 激活函数： PReLU 函数
     *
     * @param param 函数参数
     * @param a     通常为0~1内的参数
     * @return 函数值
     */
    public static double PReLU(double param, double a) {
        return param >= 0 ? param : a * param;
    }

    /**
     * PReLU 函数导数
     *
     * @param param 函数参数
     * @param a     通常为0~1内的参数
     * @return 函数值
     */
    public static double dPReLU(double param, double a) {
        return param >= 0 ? 1.0 : a;
    }

    /**
     * 激活函数： LeakyReLU 函数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double LeakyReLU(double param) {
        return param >= 0 ? param : 0.01 * param;
    }

    /**
     * LeakyReLU 函数导数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double dLeakyReLU(double param) {
        return param >= 0 ? 1.0 : 0.01;
    }

    /**
     * 激活函数： ELU 函数
     *
     * @param param 函数参数
     * @param a     系数
     * @return 函数值
     */
    public static double ELU(double param, double a) {
        return param >= 0 ? param : a * (Math.exp(param) - 1);
    }

    /**
     * ELU 函数导数
     *
     * @param param 函数参数
     * @param a     系数
     * @return 函数值
     */
    public static double dELU(double param, double a) {
        return param >= 0 ? 1.0 : a * Math.exp(param);
    }

    /**
     * 激活函数： SoftPlus 函数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double softPlus(double param) {
        return Math.log(1 + Math.exp(param));
    }

    /**
     * SoftPlus 函数导数
     *
     * @param param 函数参数
     * @return 函数值
     */
    public static double dSoftPlus(double param) {
        return Math.exp(param) / (1 + Math.exp(param));
    }


    /**
     * 激活函数：SoftMax
     *
     * @param index 索引
     * @param group 群体
     * @return 函数值
     */
    public static double softMax(int index, double... group) {
        int len = group.length;
        if (index >= len) return 1.0;
        double sum = 0.0;
        for (double v : group) {
            sum += v;
        }
        return group[index] / sum;
    }

}
